FaceIt Fortran
Volume Number: 5
Issue Number: 9
Column Tag: Fortran's World
FaceIt Saves Fortran 
By Mark McBride, Oxford, CA
Porting Number Crunching Routines
When the first Fortran articles appeared in MacTutor the goal was to discuss
porting Fortran applications to the Mac. The articles I have written evolved into a
discussion of programming the Mac interface using MacFortran. Porting Fortran
programs really meant running the program in its sequential, non-Mac, form unless
you were willing to invest substantial time re-writing the user front-end to your
code. The advent of MPW based Fortran’s (Language Systems is shipping and Absoft is
reportedly working on a MPW Fortran compiler) means we may eventually get MacApp
support. But even MacApp support would mean writing your own event loop and
window environment.
Enter FaceIt. FaceIt has been discussed previously in MacTutor. Chuck Bouldin
reviews the basics of FaceIt (formerly known as MacFace) in the July 1987 issue.
FaceIt’s author, Dan Kampmeier wrote a letter to the editor in which he presents
where FaceIt can be beneficial. While earlier versions of FaceIt made adding a Mac
interface easier for text windows and plotting graphs, most of my work as an economist
involves heavy number crunching routines. The basic structure of the Fortran
program sets up the data and parameters to be used, passes the array to a subroutine to
calculate, and then writes out the results.
Version 3.3 of FaceIt adds a feature, sheets, which dramatically increases its
value in porting number crunching Fortran programs. A sheet in FaceIt is a
spreadsheet tagged to any numeric array you choose. The user can enter and edit the
numeric values in the array with spreadsheet ease. The program can have as many as
four sheets open at once. Sheets will be explained below.
Figure 1. A Sheet
At the same time that FaceIt was adding sheets, Absoft technical support released
a subroutine which allows dynamic array allocation (phone 904 423-7587 to get a
copy). Provision of a method of dynamically allocating arrays means that the toolbox
memory manager can be used to allocate a block of memory for the array, with the size
of the array depending on available memory. When the program needs a new array of
different dimensions, the old array can be de-allocated, thus recapturing its space for
use with the new array.
Given that using FaceIt is resource intensive, I have tried to structure the article
into the main issues confronted with porting an existing number crunching program to
a Mac interface. The example program (Listing One) is a general data editor program
with a subroutine for calculating the means of the selected observations (rows) of the
selected variables (columns). The user is given the opportunity to analyze (via a
dialog) a set of variables and observations other than the current selection in the sheet
window. The source code given can be used with very little modification to move your
number crunching subroutine into a Mac interface. The structure for creating,
opening, and saving real*8 arrays is provided. Just define the appropriate arrays and
add your favorite cruncher.
Data Editor
Dynamic Arrays
Absoft has released an assembly language routine which allows a programmer to
allocate memory using the toolbox and then assign an array to the newly allocated
memory block. The process is straightforward.
• code a new main program to allocate an array (of any size) and call your original
main program as a subroutine. For example:
PROGRAM shell
real*8 thearray(1)
call main(thearray)
end
• rewrite your main program as a subroutine which accepts an array as an
argument. Continuing the example:
SUBROUTINE main(thearray)
real*8 thearray(*)
integer i,toolbx,blkptr
include memory.inc
blkptr=toolbx(NEWPTR,1024)
call dynam(blkptr)
do (i=1,100)
myarray(i)=i
repeat
call Cruncher(thearray)
call toolbx(DISPOSEPTR,blkptr)
end
SUBROUTINE Cruncher(thearray)
real*8 thearray(*)
{do something with the array}
end
• by allocating a new block of memory with the toolbox routine NEWPTR or
NEWHANDLE, as much memory as can be reasonably retrieved can be used. If you
use NEWHANDLE, be sure to lock the block in place before calling the dynam
subroutine and using the memory space.
• When using dynam, the last argument passed in the subroutine call will be
redirected to the allocated memory block. The ‘C’ compile option for detecting
array boundary overruns will not be functional and cannot be used when
compiling the program.
• To allocate a new array of a different size dispose of the old memory allocation,
allocate a new pointer or handle and then just recall dynam. For example:
Subroutine Main (thearray)
....
blkptr=toolbx(NEWPTR,1024)
call dynam(blkptr)
{... use the array ...}
call toolbx(DISPOSPTR,blkptr)
blkptr=toolbx(NEWPTR,2048)
call dynam(blkptr)
{... use the new array space ...}
...
The only other task is to do error checking. Examination of the Data Editor
program (Listing One) demonstrates simple error checking.
Event Handling
A Mac interface is programmed essentially as a continuously repeated event loop.
When the user indicates an action, then an appropriate response is made. FaceIt
simplifies adding the event driven loop by handling all the usual events in a Mac
interface: standard menus; text window events; dialogs; text cut, copy, or paste; and
sheet window events. The programmer concentrates on handling the program specific
menu selections. A simple FaceIt program has the following event loop structure:
do
call FaceIt(0,0,0,0,0,0) !give control to user
select case (MAC) !MAC tells us which menu chosen
case(‘About’)
.....{do about action}
case(‘Means’)
.....{do means action}
end select
repeat
The call FaceIt(0,0,0,0,0,0) turns control over to the FaceIt event loop, which
handles events until a user specifies a program specific menu action. Thus the
programmer need not be worried about dragging and re-sizing windows, tracking menu
actions, handling DA’s, handling text entry in a text edit window, opening or saving
text edit windows to disk, or number entry and editing in a spreadsheet window. When
the user specifies a program specific menu action, FaceIt returns control to the
programmer, passing the menu selection in the global variable MAC. Thus the
programmer focuses on handling the program specific actions, not the basic Mac
interface actions.
In the Data Editor program, one sheet window and one text edit window has been
specified by retaining only wind resources #1001 and #1006 in the program specific
copy of the FaceIt resources (more below on FaceIt resources). The FaceIt ‘File’ menu
resource has been modified to include a ‘New Sheet’ choice:
The open, save as, and append to actions are provided by FaceIt for the text edit
window. However, for the sheet window, we must provide our own open and save
routines. The print routine will print the currently active window (either the text
window or the sheet window). The only other menu added is the options menu
(ID#105) which contains one item:
When selected, the current array assigned to the sheet window is passed to the
routine which calculates the means of the selected observations. The results of the
calculations are passed back to the text editor window for viewing, printing, and
saving. Thus our program must contain code for creating a new array and tagging it to
a sheet, opening and saving the sheet (array) to binary disk files, the means routine
which operates on an array passed to it, and quitting (to insure the option of saving
changes in the current sheet to the disk file).
New Sheet
Allocation of a new sheet in FaceIt using dynamic arrays involves a few simple
steps. These steps are followed for creation of a brand new sheet or for opening into a
sheet from a saved data file (see Listing One).
• If an existing sheet exists, then call a save routine to save the existing data.
• Call a setup dialog to get the number of rows and columns for the new array.
Upon entry to the dialog, use COMPACTMEM to determine available space. Next
retrieve the number of rows and columns from the user via a dialog. Finally,
check to see if the requested number of data cells can fit in available memory
(leaving a buffer for other program use). If the array can be allocated return to
the new sheet allocation.
• If the number of cells requested can be allocated, dispose of the existing array in
the heap, then call FaceIt’s NEWBLK routine. FaceIt’s routine will provide
additional memory error handling protection over and above the toolbox routines
(NEWPTR, NEWHANDLE). NEWBLK allocates a new handle in the heap and locks
it in place.
• If the new memory is successfully allocated on the heap, call dynam to redirect
the array to new memory space.
• Finally, relate the array to the sheet and clean up the sheet display with calls to
the FaceIt routines SetSh and FixSh.
Following these steps the program can continually reuse heap space to allocate
the array to the size needed whenever the user requests a new sheet or opens into a the
sheet from a disk file. Notice allocating the array in heap space means that the
program can be used under MultiFinder and will only use space allocated to the
program.
Saving the current array to a binary disk file is a straight forward process. The
format of the binary save is nmax, kmax (the number of rows and columns), the kmax
titles, and finally the data. The steps are:
• If the user selected ‘save as’ set the current name to null. If the data has not been
previously saved (name is null), call FaceIt’s StdSav routine to use the standard
save dialog to select the disk file name. FaceIt returns the name the user selected
in the variable ‘name’.
• If the user did not click cancel, then open the disk file as unformatted and write
the data.
• Reset the sheet title to reflect the current name.
• Set the disk file type flag to ‘DPTE’ which indicates a binary data file created by
the Data Editor program.
Opening an existing binary data file into the the array is much the same process
as creating a new sheet. The binary data file must have been created with a save
command from the Data Editor program and have a file type of ‘DPTE’. The steps to
open are:
• If the user clicks cancel during any of the following steps, drop through the
routine, leaving the current array/sheet intact.
• If an existing sheet exists, then call a save routine to save the existing data.
• Call the FaceIt routine StdOpn with a file type of ‘DPTE’ passed via the variable
MAC. This will present the user with the standard file package open routine displaying
only binary data files created by Data Editor.
• Dispose the existing array in the heap, read in the number of cells in the data
file (nmax, kmax), then call FaceIt’s NEWBLK routine.
• If the new memory is successfully allocated on the heap, call dynam to redirect
the array to new memory space, then read in the titles and data values.
• Finally, relate the array to the sheet and clean up the sheet display with calls to
the FaceIt routines SetSh and FixSh.
Means
The means routine expects an array, the number of rows, and the number of
columns. A dialog is called to have the user select the observations and variables on
which to perform the analysis. The selection dialog could have been handled prior to
the call to the means routine and the selection passed as an argument to the means
subroutine. The dialog defaults to the current selection in the sheet window. The
means are calculated and then output to the text edit window starting at the current
selection point. Given the simple output nature of the means subroutine, I put the
FaceIt calls necessary to write to the text edit window in the routine. However, on
many occasions, there a substantial number of write statements. In those cases, the
write statements can be sent to a temporary disk file and then the disk file opened into
the text edit window (all with a few simple FaceIt calls).
FaceIt normally handles the quit routine, but the programmer can have FaceIt
return control during the quit sequence. The Data Editor program has a small quit
routine which asks the user if the current sheet should be saved before quitting (or
transferring) and then returns control to FaceIt to complete the quit (or transfer)
process.
Resource Basis
Using FaceIt to attach a Mac interface is a resource intensive process. Whenever
you start a new program, you copy the FaceIt resource file (called Resources) giving